﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SimpleInfrastructure.Extentions;
using SimpleInfrastructure.Helpers;
using System.Web;
using System.Web.Security;

namespace SimpleService.Authentication
{
    public class FormsAuthenticationService
    {
        protected IUser _signedInUser;
        private bool _isAuthenticated;
        private const int _cookieVersion = 3;
        protected IAuthenticationSettings _settings;
        protected IUserService _userService;
        public TimeSpan ExpirationTimeSpan { get; set; }

        public FormsAuthenticationService(IAuthenticationSettings settings,IUserService userService)
        {
            _settings = settings;
            _userService = userService;
        }

        public virtual void SignIn(IUser user, bool createPersistentCookie)
        {
            var now = DateTime.Now;
            
            var userData = String.Concat(user.UserName.ToBase64(), ";", _settings.Name);

            var ticket = new FormsAuthenticationTicket(
                _cookieVersion,
                user.UserName,
                now,
                now.Add(ExpirationTimeSpan),
                createPersistentCookie,
                userData,
                FormsAuthentication.FormsCookiePath);

            var encryptedTicket = FormsAuthentication.Encrypt(ticket);

            var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket)
            {
                HttpOnly = true,
                Secure = _settings.RequiresSSL,
                Path = FormsAuthentication.FormsCookiePath
            };

            var httpContext = EnvHelper.CurrentContext();

            if (!String.IsNullOrEmpty(_settings.RequestUrlPrefix))
            {
                cookie.Path = GetCookiePath(httpContext);
            }

            if (FormsAuthentication.CookieDomain != null)
            {
                cookie.Domain = FormsAuthentication.CookieDomain;
            }

            if (createPersistentCookie)
            {
                cookie.Expires = ticket.Expiration;
            }

            httpContext.Response.Cookies.Add(cookie);

            _isAuthenticated = true;
            _signedInUser = user;
        }
        public virtual void SignOut()
        {
            _signedInUser = null;
            _isAuthenticated = false;
            FormsAuthentication.SignOut();
            
            var httpContext = EnvHelper.CurrentContext();
            var rFormsCookie = new HttpCookie(FormsAuthentication.FormsCookieName, "")
            {
                Expires = DateTime.Now.AddYears(-1),
            };

            if (!String.IsNullOrEmpty(_settings.RequestUrlPrefix))
            {
                rFormsCookie.Path = GetCookiePath(httpContext);
            }

            httpContext.Response.Cookies.Add(rFormsCookie);
        }

        public void SetAuthenticatedUserForRequest(IUser user)
        {
            _signedInUser = user;
            _isAuthenticated = true;
        }

        public virtual IUser GetAuthenticatedUser()
        {
            if (_signedInUser != null || _isAuthenticated)
                return _signedInUser;

            var httpContext = EnvHelper.CurrentContext();
            if (!httpContext.Request.IsAuthenticated || !(httpContext.User.Identity is FormsIdentity))
            {
                return null;
            }

            var formsIdentity = (FormsIdentity)httpContext.User.Identity;
            var userData = formsIdentity.Ticket.UserData ?? "";

            // The cookie user data is {userName.Base64};{tenant}.
            var userDataSegments = userData.Split(';');

            if (userDataSegments.Length < 2)
            {
                return null;
            }

            var userDataName = userDataSegments[0];
            var userDataTenant = userDataSegments[1];

            try
            {
                userDataName = userDataName.FromBase64();
            }
            catch
            {
                return null;
            }

            if (!String.Equals(userDataTenant, _settings.Name, StringComparison.Ordinal))
            {
                return null;
            }

            _signedInUser = _userService.GetUser(userDataName);
            if (_signedInUser != null)
            {
                _isAuthenticated = true;
            }
            return _signedInUser;
        }

        private string GetCookiePath(HttpContext httpContext)
        {
            var cookiePath = httpContext.Request.ApplicationPath;
            if (cookiePath != null && cookiePath.Length > 1)
            {
                cookiePath += '/';
            }

            cookiePath += _settings.RequestUrlPrefix;

            return cookiePath;
        }
    }
}
